package sistemaClassificador.algoritmoGenetico;

import java.util.ArrayList;
import java.util.Random;

import util.Logger;
import weka.core.Instance;
import weka.core.Instances;

public class Competicao {
	private Logger log = new Logger(this);
	private Populacao    pop;
	private int          nrCompeticoes;
	private MersenneTwister       geradorRandom;
	private Configuracao config;
	private Instances    dados;
	
	public Competicao(Populacao pop,int nrCompeticoes,MersenneTwister geradorRandom,Configuracao config,Instances dados) {
		this.pop = pop;
		this.nrCompeticoes = nrCompeticoes;
		this.geradorRandom = geradorRandom;
		this.config = config;
		this.dados  = dados;
	}
	
	public void realizar() throws Exception{
		
		int maiorIndex   =  0;
		
		for(int a=0;a<nrCompeticoes;a++){
			double maiorEbid = -1;
			
			//cobra a taxa de vida
					
			double y = (double) a+1;
			double taxaVida = 1 - Math.pow((1.0/2.0), (1.0/y));
			for(int c=0;c<pop.size();c++){
				double fit;
				fit = pop.getRegra(c).getFitness() ;
				fit = fit - taxaVida;
				if(fit<0){
					fit=0;
				}
				pop.getRegra(c).setFitness(fit);
			}
		
			/*
			 * Seleciona a instancia da população 
			 */
			int      idx = 0 ; 
			Instance i   = null;
			ArrayList<Regra> lista = new ArrayList<Regra>();
			while(true){
			   idx = geradorRandom.nextInt(dados.numInstances());			   
			   i = dados.instance(idx);		
			   lista = getRegrasIguais(i,a);
			   if(lista.size()>0){
				   break;
			   }
			}
//			log.info("Competição"+a);
//			for(int b=0;b<i.numAttributes();b++){
//				log.info("Instância"+i.stringValue(b).toString());
//			}
			if(lista.size()>0){
			
			/*
			 * Calcula o bidt e ebid
			 */
			for(int b =0;b<lista.size();b++){
					
				if(lista.get(b).getFitness()>0){
				double bidt = config.getK0() * (config.getK1()+ config.getK2() * Math.pow(lista.get(b).getSpec(), config.getSpow())) * lista.get(b).getFitness() ;
				lista.get(b).setBidt(bidt);
				double nt = geradorRandom.nextDouble();
				Math.abs(nt);
				double ebid = bidt*(1 + nt);
				lista.get(b).setEbid(ebid);
				/*
				 * Cobrar a taxa de participação do conjunto de regras
				 */
				double taxa = config.getBidTax()*lista.get(b).getBidt();
				lista.get(b).setFitness(lista.get(b).getFitness() - taxa);
		
				/*
				 * Encontra a regra com  maior ebid
				 */
				if(ebid > maiorEbid){
					maiorEbid = ebid;
					maiorIndex = b;
				}
				}
			}
			
			
	//		for(int b=0;b<lista.size();b++){
	//		    log.info("Regra"+b+"Fitness:"+lista.get(b).getFitness()+" Classe : "+lista.get(b).getClasse());
	//		    log.info("Ebid"+lista.get(b).getEbid());
	//		    for(int x=0;x<(dados.numAttributes()-1);x++){
	//				log.info("Atributo: "+x+ lista.get(b).getCondicao(x));
	//				
	//			}
	//		}
			
	//		log.info("Vencedor = "+maiorIndex);
	    
			/*
			 *  Atua sobre o ambiente 
			 *  verifica se a regra acertou ou errou
			 */
			
			double novoFit=0;
			if(lista.get(maiorIndex).getClasse().equals(i.stringValue(i.numAttributes()-1))){
				novoFit = lista.get(maiorIndex).getFitness()*(1+config.getPercRecompensa());
			}else{
				novoFit = lista.get(maiorIndex).getFitness()*(1-config.getPercRecompensa());
				// hierarquia = 	hierarquia = dijkstra(lista.get(maiorIndex).getClasse(),
//						i.stringValue(i.numAttributes() - 1).toString());
			}
			/*
			 * Recompensa ou punição a regra
			 */
		
			lista.get(maiorIndex).setFitness(novoFit);
	
			
		//	log.info("Regra"+maiorIndex+"TaxaVida:"+taxaVida);
		//	log.info("Regra"+maiorIndex+"Spec:"+lista.get(maiorIndex).getSpec());
		//	log.info("Regra"+maiorIndex+"Ebid:"+lista.get(maiorIndex).getEbid());
		//	log.info("Regra"+maiorIndex+"Bidt:"+lista.get(maiorIndex).getBidt());	
	///		log.info("Regra"+maiorIndex+"NovoFitness:"+lista.get(maiorIndex).getFitness());
		//	log.info("Novo Fit = "+novoFit);
		//	log.info("Taxa = "+taxaVida);
			}
		}
		
	}

	private ArrayList<Regra> getRegrasIguais(Instance i, int a) {
		ArrayList<Regra> l = new ArrayList<Regra>();
		
		for(int c=0;c<pop.size();c++){
		  Regra t = pop.getRegra(c);
		  int b=0;
		  if(pop.getRegra(c).getFitness()>0){
								
			for(b=0;b<i.numAttributes()-1;b++){
				try {
					if(t.getCondicao(b).isAtivo()){
						if(!t.getCondicao(b).getElemento().equals(i.stringValue(b).toString())){
							break;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(b==i.numAttributes()-1){
				l.add(pop.getRegra(c));
			}
		}
		}	
		return l;
	}
	

	
}
